//------------------------------------------------------------------------------
// Copyright (c) 2008 www.dnaide.com
// Licensed under the MIT (MIT-LICENSE.txt)
//------------------------------------------------------------------------------
using System;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.UI;
using System.Web;
using System.Text;
using System.IO;

using DNAide.Core;
using DNAide.Data;
using DNAide.Web;

namespace DNAide.Web.UI.Controls
{
	/// <summary>
	/// Generates a page to be used to page through record sets. Rather than using buttons or postbacks, the generated HTML are page links. This is great for spiders etc crawling your site.
	/// </summary>
	public class HyperLinkPager : Control
	{

		#region Attribtues

		private int _pageIndex;
		private int _totalPages;
		private int _halfMaxPagesToDisplay;

		#endregion


		#region Properties

		/// <summary>
		/// Override how this control handles its controls collection
		/// </summary>
		public override ControlCollection Controls
		{
			get
			{
				EnsureChildControls();
				return base.Controls;
			}

		}

		private bool HasPrevious
		{
			get
			{
				if (PageIndex > 0)
					return true;
				return false;
			}
		}

		private bool HasNext
		{
			get
			{
				if (PageIndex + 1 < TotalPages)
					return true;
				return false;
			}
		}

		private bool HasFirst
		{
			get
			{
				if ((PageIndex >= HalfMaxPagesToDisplay) && (TotalPages > MaxPagesToDisplay))
					return true;
				else
					return false;
			}
		}

		private bool HasLast
		{
			get
			{
				if (((PageIndex + HalfMaxPagesToDisplay) < TotalPages) && (TotalPages > MaxPagesToDisplay))
					return true;
				else
					return false;
			}
		}

		private int HalfMaxPagesToDisplay
		{
			get
			{
				if (_halfMaxPagesToDisplay < 1)
				{
					// First calculate the division
					_halfMaxPagesToDisplay = MaxPagesToDisplay / 2;

					// Now do a mod for any remainder
					if ((MaxPagesToDisplay % 2) > 0)
						_halfMaxPagesToDisplay++;
				}
				return _halfMaxPagesToDisplay;
			}
		}
		
		/// <summary>
		/// </summary>
		public int TotalPages
		{
			get
			{
				if (_totalPages < 0)
				{
					_totalPages = DataAide.CalculateTotalPages(TotalRecords, PageSize);
				}
				return _totalPages;
			}
		}

		/// <summary>
		/// </summary>
		public Boolean ShowPageSummary
		{
			get { return ((ViewState["ShowPageSummary"] == null) ? true : (bool)ViewState["ShowPageSummary"]); }
			set { ViewState["ShowPageSummary"] = value; }
		}

		/// <summary>
		/// </summary>
		public Boolean ShowFirst
		{
			get { return ((ViewState["ShowFirst"] == null) ? true : (bool)ViewState["ShowFirst"]); }
			set { ViewState["ShowFirst"] = value; }
		}

		/// <summary>
		/// </summary>
		public Boolean ShowLast
		{
			get { return ((ViewState["ShowLast"] == null) ? true : (bool)ViewState["ShowLast"]); }
			set { ViewState["ShowLast"] = value; }
		}

		/// <summary>
		/// </summary>
		public String PageSummaryStringFormat
		{
			get { return ((ViewState["PageSummaryStringFormat"] == null) ? Resources.HyperLinkPager.PageSummaryStringFormat : (string)ViewState["PageSummaryStringFormat"]); }
			set { ViewState["PageSummaryStringFormat"] = value; }
		}

		/// <summary>
		/// </summary>
		public String FirstPageText
		{
			get { return ((ViewState["FirstPageText"] == null) ? Resources.HyperLinkPager.FirstPageText : (string)ViewState["FirstPageText"]); }
			set { ViewState["FirstPageText"] = value; }
		}

		/// <summary>
		/// </summary>
		public String LastPageText
		{
			get { return ((ViewState["LastPageText"] == null) ? Resources.HyperLinkPager.LastPageText : (string)ViewState["LastPageText"]); }
			set { ViewState["LastPageText"] = value; }
		}

		/// <summary>
		/// </summary>
		public String PreviousPageText
		{
			get { return ((ViewState["PreviousPageText"] == null) ? Resources.HyperLinkPager.PreviousPageText : (string)ViewState["PreviousPageText"]); }
			set { ViewState["PreviousPageText"] = value; }
		}

		/// <summary>
		/// </summary>
		public String NextPageText
		{
			get { return ((ViewState["NextPageText"] == null) ? Resources.HyperLinkPager.NextPageText : (string)ViewState["NextPageText"]); }
			set { ViewState["NextPageText"] = value; }
		}

		/// <summary>
		/// </summary>
		public String LinkUrl
		{
			get { return ((ViewState["LinkUrl"] == null) ? HttpContext.Current.Request.Url.AbsoluteUri.ToString() : (string)ViewState["LinkUrl"]); }
			set { ViewState["LinkUrl"] = value; }
		}

		/// <summary>
		/// </summary>
		public String PageIndexParameterName
		{
			get { return ((ViewState["PageIndexParameterName"] == null) ? "pageindex" : (string)ViewState["PageIndexParameterName"]); }
			set { ViewState["PageIndexParameterName"] = value; }
		}

		/// <summary>
		/// </summary>
		public virtual Int32 PageIndex
		{
			get
			{
				HttpContext context = HttpContext.Current;

				if (Page.IsPostBack && ViewState["PageIndex"] != null)
				{
					_pageIndex = CastAide.AsInt32(ViewState["PageIndex"]);
				}
				else
				{
					if (context.Request[PageIndexParameterName] != null)
						_pageIndex = CastAide.AsInt32(context.Request[PageIndexParameterName]) - 1;
				}

				if (_pageIndex < 0)
					return 0;
				else
					return _pageIndex;
			}
			set
			{
				ViewState["PageIndex"] = value;
				_pageIndex = value;
			}
		}

		/// <summary>
		/// </summary>
		public virtual Int32 PageSize
		{
			get
			{
				int pageSize = Convert.ToInt32(ViewState["PageSize"]);

				if (pageSize == 0)
					return 20;

				return pageSize;
			}
			set
			{
				ViewState["PageSize"] = value;
			}
		}

		/// <summary>
		/// </summary>
		public Int32 TotalRecords
		{
			get { return ((ViewState["TotalRecords"] == null) ? 0 : (int)ViewState["TotalRecords"]); }
			set { ViewState["TotalRecords"] = value; }
		}

		/// <summary>
		/// </summary>
		public Int32 MaxPagesToDisplay
		{
			get 
			{
				int retval = CastAide.AsInt32Invariant(ViewState["MaxPagesToDisplay"], 5);
				if (retval < 2)
				{
					retval = 5;
				}
				return retval;
			}
			set { ViewState["MaxPagesToDisplay"] = value; }
		}

		/// <summary>
		/// </summary>
		public String CssClass
		{
			get { return ((ViewState["CssClass"] == null) ? "hyperlink-pager" : (string)ViewState["CssClass"]); }
			set { ViewState["CssClass"] = value; }
		}

		#endregion

		/// <summary>
		/// </summary>
		public HyperLinkPager()
		{
			_pageIndex = 0;
			_totalPages = -1;
			_halfMaxPagesToDisplay = 0;
		}


		#region Helper Methods

		private string CreatePagerURL(string pageIndex)
		{
			return UrlAide.ChangeQueryStringValueInUrl(LinkUrl, PageIndexParameterName, pageIndex.ToString());
		}

		#endregion


		#region Render functions

		/// <summary>
		/// </summary>
		protected override void CreateChildControls()
		{
			Controls.Clear();
		}

		/// <summary>
		/// </summary>
		/// <param name="writer"></param>
		protected override void Render(HtmlTextWriter writer)
		{
			// Nothing found so nothing to render
			if (TotalPages <= 1)
				return;

			writer.WriteBeginTag("div");
			writer.WriteAttribute("id", ClientID);
			if (!String.IsNullOrEmpty(CssClass))
			{
				writer.WriteAttribute("class", CssClass);
			}
			writer.Write(HtmlTextWriter.TagRightChar);

			if (ShowPageSummary)
				RenderPageSummary(writer);

			RenderPages(writer);
			
			writer.WriteEndTag("div");
		}

		void RenderPageSummary(HtmlTextWriter writer)
		{
			writer.WriteBeginTag("div");
			writer.WriteAttribute("class", "page-summary");
			writer.Write(HtmlTextWriter.TagRightChar);
			writer.Write(String.Format(PageSummaryStringFormat, (PageIndex + 1), TotalPages, TotalRecords));
			writer.WriteEndTag("div");
		}

		void RenderPages(HtmlTextWriter writer)
		{
			writer.WriteBeginTag("div");
			writer.WriteAttribute("class", "page-links");
			writer.Write(HtmlTextWriter.TagRightChar);
			writer.WriteBeginTag("ul");
			writer.Write(HtmlTextWriter.TagRightChar);

			// Render the first button
			RenderFirst(writer);

			// Render the previous button
			RenderPrevious(writer);

			// Render the page button(s)
			RenderPagingLinks(writer);

			// Render the next button
			RenderNext(writer);

			// Render the last button
			RenderLast(writer);

			writer.WriteEndTag("ul");
			writer.WriteEndTag("div");
		}

		void RenderFirst(HtmlTextWriter writer)
		{
			if (!ShowFirst)
				return;

			if (HasFirst)
			{
				writer.WriteBeginTag("li");
				writer.WriteAttribute("class", "first-page");
				writer.Write(HtmlTextWriter.TagRightChar);

				HyperLink link = new HyperLink();
				link.Text = FirstPageText;
				link.NavigateUrl = CreatePagerURL("1");
				link.RenderControl(writer);

				writer.WriteEndTag("li");
			}
		}

		void RenderLast(HtmlTextWriter writer)
		{
			if (!ShowLast)
				return;

			if (HasLast)
			{
				writer.WriteBeginTag("li");
				writer.WriteAttribute("class", "last-page");
				writer.Write(HtmlTextWriter.TagRightChar);

				HyperLink link = new HyperLink();
				link.Text = LastPageText;
				link.NavigateUrl = CreatePagerURL(TotalPages.ToString());
				link.RenderControl(writer);

				writer.WriteEndTag("li");
			}
		}

		void RenderPrevious(HtmlTextWriter writer)
		{
			if (HasPrevious)
			{
				writer.WriteBeginTag("li");
				writer.WriteAttribute("class", "previous-page");
				writer.Write(HtmlTextWriter.TagRightChar);

				int previousPage;
				if (PageIndex < 2)
					previousPage = 1;
				else
					previousPage = PageIndex;

				HyperLink link = new HyperLink();
				link.Text = PreviousPageText;
				link.NavigateUrl = CreatePagerURL(previousPage.ToString());
				link.RenderControl(writer);

				writer.WriteEndTag("li");
			}
		}

		void RenderNext(HtmlTextWriter writer)
		{
			if (HasNext)
			{
				writer.WriteBeginTag("li");
				writer.WriteAttribute("class", "next-page");
				writer.Write(HtmlTextWriter.TagRightChar);

				int nextPage = PageIndex + 2;

				HyperLink link = new HyperLink();
				link.Text = NextPageText;
				link.NavigateUrl = CreatePagerURL(nextPage.ToString());
				link.RenderControl(writer);

				writer.WriteEndTag("li");
			}
		}

		void RenderPagingLinks(HtmlTextWriter writer)
		{
		  Page.Trace.Write(StringAide.FormatInvariant("PageIndex: {0}<br />", PageIndex));

			Page.Trace.Write(StringAide.FormatInvariant("MaxPagesToDisplay: {0}<br />", MaxPagesToDisplay));

			Page.Trace.Write(StringAide.FormatInvariant("HalfMaxPagesToDisplay: {0}<br />", HalfMaxPagesToDisplay));

			int lowerBound = 0;
			int upperBound = 0;
			if (TotalPages <= MaxPagesToDisplay)
			{
				// Total number of pages is <= the max number of pages to display at once - so display all
				lowerBound = 0;
				upperBound = TotalPages;
				Page.Trace.Write(StringAide.FormatInvariant("Will Render a: {0} - {1}<br />", 0, TotalPages));
			}
			else
			{
				// Total pages > MaxPagesToDisplay
				lowerBound = PageIndex - (HalfMaxPagesToDisplay - 1);
				Page.Trace.Write(StringAide.FormatInvariant("Lower bound pt1: {0}<br />", lowerBound));
				if (lowerBound < 0)
					lowerBound = 0;

				upperBound = lowerBound + MaxPagesToDisplay;
				Page.Trace.Write(StringAide.FormatInvariant("Upper bound pt1: {0}<br />", upperBound));
				if (upperBound > TotalPages)
				{
					// How much is it over by?
					int diff = (upperBound - TotalPages) * -1;
					Page.Trace.Write(StringAide.FormatInvariant("Diff: {0}<br />", diff));
					lowerBound += diff;
					upperBound = TotalPages;
				}
				Page.Trace.Write(StringAide.FormatInvariant("Will Render b: {0} - {1}<br />", lowerBound, upperBound));
			}

			for (int i = lowerBound; i < upperBound; i++)
			{
				writer.WriteBeginTag("li");
				if (PageIndex == i)
				{
					writer.WriteAttribute("class", "page current");
				}
				else
				{
					writer.WriteAttribute("class", "page");
				}
				writer.Write(HtmlTextWriter.TagRightChar);

				int pageIndexToDisplay = i + 1;
				HyperLink link = new HyperLink();
				link.Text = pageIndexToDisplay.ToString();
				link.NavigateUrl = CreatePagerURL(pageIndexToDisplay.ToString());
				link.RenderControl(writer);

				writer.WriteEndTag("li");
			}
		}

		#endregion

	}
}
